package com.abhinav;

import com.abhinav.LinkedList.Node;

public class HashMap {

	// Bucket
	int bucket_size = 10;
	Object[] bucket;

	public HashMap(int bucketSize) {
		this.bucket_size = bucketSize;
		bucket = new Object[bucket_size];
	}

	public HashMap() {
		bucket = new Object[bucket_size];
	}

	/**
	 * Add key, value pair in the HashMap
	 * 
	 * @param key
	 * @param value
	 */
	public void add(Object key, Object value) {
		int kCode = key.hashCode();
		int index = kCode % bucket_size;

		System.out.println("->" + index);

		if (bucket[index] == null) {
			System.out.println("First entry in Bucket: Key=" + key);
			HashNode node = new HashNode();
			node.key = key;
			node.value = value;

			bucket[index] = node;
		} else {
			// value already exists, so add this element into LinkedList
			HashNode node = (HashNode) bucket[index];
			System.out.println("Add into List of: " + node.key + " Key=" + key);
			// initiate the list
			node.initList();

			HashNode newNode = new HashNode();
			newNode.key = key;
			newNode.value = value;

			// add the new element into list
			node.list.addLast(newNode);
		}
	}

	/**
	 * If the key is not present, it will return null
	 * 
	 * @param key
	 * @return
	 */
	public Object get(Object key) {
		int index = key.hashCode() % bucket_size;
		System.out.println("Searching for Bucket Index: " + index);

		if (index >= bucket.length) {
			new ArrayIndexOutOfBoundsException("Invalid Attempt: Index=" + index);
		}

		// fetch the node at the index
		HashNode node = (HashNode) bucket[index];

		if (null == node) {
			// At this position there is no node in the bucket
			return null;
		}

		if (node.key.hashCode() == key.hashCode()) {
			// element is found in the bucket
			System.out.println("1st Level Match....");
			return node.value;
		}

		// unable to find in the element in the bucket, find in the associated
		// list
		java.util.LinkedList<Object> list = node.list;

		if (list == null) {
			System.out.println("No associated list");
			return null;
		}

		// pointer to the root node of the linkedlist
		Node first = (Node) list.getFirst();

		while (true) {
			if (first == null)
				break;
			HashNode hn = (HashNode) first.data();
			if (key.hashCode() == hn.key.hashCode()) {
				System.out.println("2nd Level Match Found...");
				return hn.value;
			}
			first = first.next();
		}

		// still unable to find the element
		System.out.println("Failed to hit bulls eye!! No match found");
		return null;

	}

}
